/*
 * Background Flickr: Copyright (C) 2009  Craig McNicholas
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.ddw.app.bflickr.flickr.api.url;

import com.ddw.app.bflickr.logging.Log;
import com.ddw.app.bflickr.logging.LogFactory;


/**
 * Class used to build a flickr get public photos  
 * REST url ready for requesting data.
 * This class will create a url which searches for 
 * a flickr users public photos by supplying a valid 
 * flickr accounts NSID. The number of results, which 
 * page to show, content filters and other attributes 
 * can also be adjusted.
 * @author craig
 *
 */
public class FlickrGetPublicPhotosURL extends FlickrApiURL implements FlickrPhotosURL {

	/**
	 * The service method name to use in the query string of a flickr api 
	 * REST service call.
	 */
	public static final String SERVICE_METHOD = "flickr.people.getPublicPhotos";
	
	/**
	 * The NSID query string and item key referring to the users account id 
	 * held in the extra parameters.
	 */
	private static final String KEY_NSID = "user_id";
	
	/**
	 * The safe search query string and item key referring to the type of content 
	 * to display held in the extra parameters.
	 */
	private static final String KEY_SAFE_SEARCH = "safe_search";
	
	/**
	 * The items per page query string and item key referring to the amount of photo links 
	 * to display held in the extra parameters.
	 */
	private static final String KEY_PER_PAGE = "per_page";
	
	/**
	 * The page query string and item key referring to the page number to start displaying 
	 * image links (pagination) held in the extra parameters.
	 */
	private static final String KEY_PAGE = "page";
	
	/**
	 * The default search type for photos, can limit content that may not be acceptible
	 */
	private static final FlickrSafeSearchType DEFAULT_SEARCH_TYPE = FlickrSafeSearchType.SAFE;
	
	/**
	 * The default number of photos per page to return
	 */
	private static final int DEFAULT_PHOTOS_PER_PAGE = 12;
	
	/**
	 * The default page number to return
	 */
	private static final int DEFAULT_PHOTOS_PAGE = 1;
	
	private Log log = LogFactory.createInstance(this.getClass());
	private FlickrSafeSearchType safeSearchType;
	private int photosPerPage;
	private int photosPage;
	
	/**
	 * Enumeration for safe search types
	 * @author craig
	 */
	public enum FlickrSafeSearchType {
		SAFE (),
		MODERATED (),
		RESTRICTED ();
		
		private Log log = LogFactory.createInstance(this.getClass());
		private final String SAFE_VAL = "1";
		private final String MODERATED_VAL = "2";
		private final String RESTRICTED_VAL = "3";
		
		public String toString(){
	        switch(this) {
	            case SAFE: return SAFE_VAL;
	            case MODERATED:  return MODERATED_VAL;
	            case RESTRICTED:  return RESTRICTED_VAL;
	        }
	        log.error("Could not assert the value of the enumerated type " + this);
	        throw new AssertionError("Could not assert the value of the enumerated type " + this);
	    }
	}
	
	/**
	 * Creates a new flickr api url instance for using the REST api get public photos 
	 * service available at flickr.com. This url is used to request a list of photos from a
	 * flickr account matching the NSID.
	 * @param apiKey the unique application key
	 * @param NSID the NSID to identify the user account and find public photos for
	 * @param type the search type. This can help stop sensitive images from being returned
	 * @param photosPerPage the number of photos to show per page
	 * @param page the page number to show (for pagination)
	 * @throws IllegalArgumentException when the api key is null, the NSID is null or empty, 
	 * the type is null, the number of photos or page is less than or equal to zero 
	 * <i>api keys cannot be null, the NSID cannot be null or empty, the number of pages 
	 * and page cannot be less than or equal to zero</i>
	 */
	public FlickrGetPublicPhotosURL(String apiKey, String NSID, FlickrSafeSearchType type, int numberOfPhotos, int page) throws IllegalArgumentException {
		super(FlickrApiMethod.GET_PUBLIC_PHOTOS, apiKey);
		setNSID(NSID);
		setSearchType(type);
		setPhotosPerPage(numberOfPhotos);
		setPage(page);
	}
	
	/**
	 * Creates a new flickr api url instance for using the REST api get public photos 
	 * service available at flickr.com. This url is used to request a list of photos from a
	 * flickr account matching the NSID.
	 * @param apiKey the unique application key
	 * @param NSID the NSID to identify the user account and find public photos for
	 * @throws IllegalArgumentException when the api key is null or the NSID is null or empty, <i>api keys cannot be null and the NSID cannot be null or empty</i>
	 */
	public FlickrGetPublicPhotosURL(String apiKey, String NSID) throws IllegalArgumentException {
		this(apiKey, NSID, DEFAULT_SEARCH_TYPE, DEFAULT_PHOTOS_PER_PAGE, DEFAULT_PHOTOS_PAGE);
	}
	
	/**
	 * Creates a new flickr api url instance for using the REST api get public photos 
	 * service available at flickr.com. This url is used to request a list of photos from a
	 * flickr account matching the NSID.
	 * @param apiKey the unique application key
	 * @param NSID the NSID to identify the user account and find public photos for
	 * @param type the search type. This can help stop sensitive images from being returned
	 * @throws IllegalArgumentException when the api key is null, the NSID is null or empty, 
	 * the type is null, <i>api keys cannot be null, the NSID cannot be null or empty, the 
	 * type cannot be null</i>
	 */
	public FlickrGetPublicPhotosURL(String apiKey, String NSID, FlickrSafeSearchType type) throws IllegalArgumentException {
		this(apiKey, NSID, type, DEFAULT_PHOTOS_PER_PAGE, DEFAULT_PHOTOS_PAGE);
	}
	
	/**
	 * Getter of the flickr accounts NSID to search for on flickr
	 * @return the flickr accounts NSID to append to the querystring
	 */
	public String getNSID() {
		if(hasExtraParam(KEY_NSID)) {
			return this.getExtraParams().get(KEY_NSID);
		}
		log.warn("cannot find extra parameter " + KEY_NSID);
		return null;
	}
	
	/**
	 * Setter of the flickr accounts NSID to search for on flickr
	 * @return the flickr accounts NSID to append to the querystring
	 */
	public void setNSID(String NSID) {
		if(NSID == null) {
			log.error("The flickr accounts NSID cannot be null");
			throw new IllegalArgumentException("The flickr accounts NSID cannot be null");
		}
		if(NSID.trim().length() == 0) {
			log.error("The flickr accounts NSID cannot be empty");
			throw new IllegalArgumentException("The flickr accounts NSID cannot be empty");
		}
		setExtraParam(KEY_NSID, NSID);
	}
	
	/**
	 * Getter of the flickr safe search type used when searching images on flickr
	 * @return the flickr safe search type to append to the querystring
	 */
	public FlickrSafeSearchType getSearchType() {
		if(hasExtraParam(KEY_SAFE_SEARCH)) {
			return this.safeSearchType;
		}
		log.warn("cannot find extra parameter " + KEY_SAFE_SEARCH);
		return null;
	}
	
	/**
	 * Setter of the flickr safe search type used when searching images on flickr
	 * @return the flickr safe search type to append to the querystring
	 */
	public void setSearchType(FlickrSafeSearchType type) {
		if(type == null) {
			log.error("The flickr accounts seach type cannot be null");
			throw new IllegalArgumentException("The flickr accounts seach type cannot be null");
		}
		setExtraParam(KEY_SAFE_SEARCH, type.toString());
		this.safeSearchType = type;
	}
	
	/**
	 * Getter of the number of photos to retrieve links for when searching images on flickr
	 * @return the number of photos to show per page to append to the querystring
	 */
	public int getPhotosPerPage() {
		if(hasExtraParam(KEY_PER_PAGE)) {
			return this.photosPerPage;
		}
		log.warn("There was an error obtaining the number of photos per page. The class may not have been initialised properly.");
		throw new AssertionError("There was an error obtaining the number of photos per page. The class may not have been initialised properly.");
	}
	
	/**
	 * Setter of the number of photos to retrieve links for when searching images on flickr
	 * @return the number of photos to show per page to append to the querystring
	 */
	public void setPhotosPerPage(int numberOfPhotos) {
		if(numberOfPhotos <= 0) {
			log.error("The number of photos to display per page cannot be less than or equal to zero");
			throw new IllegalArgumentException("The number of photos to display per page cannot be less than or equal to zero");
		}
		setExtraParam(KEY_PER_PAGE, Integer.toString(numberOfPhotos));
		this.photosPerPage = numberOfPhotos;
	}
	
	/**
	 * Getter of the page to show when searching images on flickr. 
	 * <i><b>This value is <u>NOT</u> ZERO indexed</b></i>
	 * @return the page to show and append to the querystring
	 */
	public int getPage() {
		if(hasExtraParam(KEY_PAGE)) {
			return this.photosPage;
		}
		log.warn("There was an error obtaining the page number. The class may not have been initialised properly.");
		throw new AssertionError("There was an error obtaining the page number. The class may not have been initialised properly.");
	}
	
	/**
	 * Setter of the page to show when searching images on flickr. 
	 * <i><b>This value is <u>NOT</u> ZERO indexed</b></i>
	 * <i>the requests are paginated and the number of photos per page is 
	 * determined by the photos per page property</i>
	 * @return the page to show and append to the querystring
	 */
	public void setPage(int page) {
		if(page <= 0) {
			log.error("The page number to display cannot be less than or equal to zero");
			throw new IllegalArgumentException("The page number to display cannot be less than or equal to zero");
		}
		setExtraParam(KEY_PAGE, Integer.toString(page));
		this.photosPage = page;
	}

}
